package cn.itcast.order.web;

import cn.itcast.order.entity.Order;
import cn.itcast.order.model.req.CreateOrderOfHighConcurrencyReq;
import cn.itcast.order.service.OrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.orz.cloud.common.result.ResultDTO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 虎哥
 */
@RestController
@RequestMapping("order")
@Slf4j
@Api(tags = "订单")
public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    /**
     * 创建订单
     * seata功能演示，可以在被调用的模块中手动抛出异常来体验分布式事务的全局异常回滚机制
     */
    @PostMapping("createOrder")
    public ResultDTO<Long> createOrder(Order order){
        log.info("调用接口");
        Long orderId = orderService.create(order);
        return ResultDTO.success(orderId);
    }

    /**
     * 高并发场景下创建订单，参考内容：
     * https://www.jianshu.com/p/7a026f630805
     * https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/RedisTemplate.html
     * https://blog.csdn.net/psiitoy/article/details/73201114
     * 主要原理就是使用redis的事务来保证商品不会超卖
     *
     * ps：
     * 在实际业务中，有两种扣减库存的方式供商户自行选择：
     * 1.下单减库存————买家下单之后就直接扣减库存
     *  特点：可以防止出现超卖的情况
     *  问题：可能出现恶意下单的情况，即大量用户下单但是不支付
     * 2.付款后减库存————买家下单，并且支付之后才扣减库存
     *  特点：可以防止恶意下单的情况，因为只有用户真正付款了，库存才会扣减
     *  问题：可能会出现超卖的情况
     *
     * 那么在秒杀这种业务中，重点是要防止超卖，所以要选择下单即减库存的方案。
     *
     * 所以这里使用的方案就是下单减库存。
     */
    @PostMapping("createOrderOfHighConcurrency")
    @ApiOperation("高并发场景下创建订单")
    public ResultDTO createOrderOfHighConcurrency(@RequestBody CreateOrderOfHighConcurrencyReq req){
        orderService.createOrderOfHighConcurrency(req);
        return ResultDTO.success();
    }

    @PostMapping("testThreadTransaction")
    public ResultDTO<String> testThreadTransaction(){
        log.info("测试线程与事务");
        orderService.testThreadTransaction();
        return ResultDTO.success("执行成功");
    }
}
